package com.pan.service.impl;

import com.pan.annotation.CouponCheck;
import com.pan.annotation.OrderItemsCheck;
import com.pan.dao.order1.OrderTable1Dao;
import com.pan.dao.order2.OrderTable2Dao;
import com.pan.entity.OrderTable1;
import com.pan.entity.OrderTable2;
import com.pan.entity.Result;
import com.pan.enume.ResultEnum;
import com.pan.feign.CouponFeign;
import com.pan.service.OrderCreateService;
import com.pan.tools.ConvertObject;
import com.pan.tools.RedisTools;
import com.pan.vo.CouponShowVo;
import com.pan.vo.OrderItemVo;
import com.pan.vo.RelationCategoryVo;
import com.pan.vo.RelationGoodsVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

@Service("OrderCreateService")
public class OrderCreateServiceImpl implements OrderCreateService {

    @Resource
    private OrderTable2Dao orderTable2Dao;

    @Resource
    private OrderTable1Dao orderTable1Dao;

    @Resource
    private CouponFeign couponFeign;

    @Resource
    private RedisTools redisTools;

    @OrderItemsCheck
    @Override
    public Result createOrderNoCoupon(String userTicket, String address,List<OrderItemVo> orderItems) {
        Optional<Double> total =  orderItems.stream().map(OrderItemVo::getTotalAmount).reduce((a,b)->a+b);
        Map<Object, Object> userMap = redisTools.hgetall("user:"+userTicket).getData();
        OrderTable1 orderTable1 = new OrderTable1()
                .setOrder1Status(0)
                .setCreateDate(new Timestamp(System.currentTimeMillis()))
                .setAddress((String) userMap.get("address"))
                .setDistrictId((Integer) userMap.get("districtId"))
                .setUserId((Long) userMap.get("userId"))
                .setTotalAmount(total.get())
                .setAddress(address)
                .setPayAmount(total.get());
        return insertOrder(orderItems, orderTable1);
    }

    @Transactional
    public Result insertOrder(List<OrderItemVo> orderItems, OrderTable1 orderTable1) {
        orderTable1Dao.insert(orderTable1);
        Long id = orderTable1.getId();
        Function<OrderItemVo, OrderTable2> toOrder2 = orderItemVo -> {
            OrderTable2 orderTable2 = ConvertObject.convertObject(new OrderTable2(),orderItemVo);
            orderTable2.setPid(id).setOrder2Status(0);
            return orderTable2;
        };
        List<OrderTable2> orderTable2List = orderItems.stream().map(toOrder2).collect(Collectors.toList());

        orderTable2Dao.insertList(orderTable2List);
        return new Result(ResultEnum.SUCCESS).setData(id);
    }


    @CouponCheck
    @OrderItemsCheck
    @Override
    public Result createOrder(String userTicket,String address, List<OrderItemVo> orderItems,Long couponHistoryId){
        Result<CouponShowVo> couponShowVoResult = couponFeign.selectCouponInfo(couponHistoryId);
        if (couponShowVoResult.getCode()!=200){
            return couponShowVoResult;
        }
        Set<Long> buyGoodsIds = new HashSet<>();
        Set<Long> buyCategoryIds = new HashSet<>();
        Consumer<OrderItemVo> addGoodsIdAndCategoryId = orderItemVo -> {
            buyGoodsIds.add(orderItemVo.getGoodsId());
            buyCategoryIds.add(orderItemVo.getCategoryId());
        };
        orderItems.stream().forEach(addGoodsIdAndCategoryId);
        CouponShowVo couponShowVo = couponShowVoResult.getData();
        List<RelationCategoryVo> relationCategoryVoList = couponShowVo.getCategoryList();
        List<RelationGoodsVo> relationGoodsVoList = couponShowVo.getGoodsList();
        Optional<List> optionalCategoryList = Optional.ofNullable(relationCategoryVoList);
        Optional<List> optionalGoodsList = Optional.ofNullable(relationGoodsVoList);
        Set<Long> goodsIdSet = new HashSet<>();
        Set<Long> categoryIdSet = new HashSet<>();
        Consumer idAddSet = relationVo -> {
            if (relationVo.getClass() == RelationGoodsVo.class){
                goodsIdSet.add(((RelationGoodsVo)relationVo).getGoodsId());
            }
            else if (relationVo.getClass() == RelationCategoryVo.class){
                categoryIdSet.add(((RelationCategoryVo)relationVo).getCategoryId());
            }
            else {
                throw new RuntimeException();
            }
        } ;
        Result couponErrorResult =  new Result(403,"优惠券不适用该订单");
        if (optionalGoodsList.isPresent()&&optionalGoodsList.get().size()!=0){
            relationGoodsVoList.stream().forEach(idAddSet);
            if (!goodsIdSet.containsAll(buyGoodsIds)){
                return couponErrorResult;
            }
        }
        if (optionalCategoryList.isPresent()&&optionalCategoryList.get().size()!=0){
            relationCategoryVoList.stream().forEach(idAddSet);
            if (!categoryIdSet.containsAll(buyCategoryIds)){
                return couponErrorResult;
            }
        }
        BinaryOperator<Double> sum = (a,b)-> a + b;
        Double total =  orderItems.stream().map(OrderItemVo::getTotalAmount).reduce(sum).get();
        Double payAmount = total-couponShowVo.getAmount();
        payAmount = payAmount<0?0d:payAmount;
        Map<Object, Object> userMap = redisTools.hgetall("user:"+userTicket).getData();
        OrderTable1 orderTable1 = new OrderTable1()
                .setOrder1Status(0)
                .setCreateDate(new Timestamp(System.currentTimeMillis()))
                .setAddress((String) userMap.get("address"))
                .setDistrictId(Integer.parseInt((String) userMap.get("districtId")))
                .setUserId(Long.parseLong((String) userMap.get("id")))
                .setTotalAmount(total)
                .setPayAmount(payAmount)
                .setPriceReduction(couponShowVo.getAmount())
                .setScorePriceReduction(total/10)
                .setPayType(0)
                .setAddress(address)
                .setCouponPriceReduction(couponShowVo.getAmount());
        return insertOrder(orderItems, orderTable1);
    }


}
